package com.cx.zyx.modulebiz.news.config;

import io.lettuce.core.ReadFrom;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.StringUtils;

import java.time.Duration;
import java.util.HashSet;
import java.util.Set;

public class RedisMasterSlaveConfig {
    // 通过 @Value 从属性文件获取配置
    @Value("${redis.sentinel.master-name:mymaster}") // 默认值 mymaster
    private String masterName;

    @Value("${redis.sentinel.nodes:127.0.0.1:26379}")
    private String nodes; // 逗号分隔的IP:Port字符串

    @Value("${redis.password:}") // 如果有密码，这里配置
    private String password;

    @Bean
    public RedisSentinelConfiguration redisSentinelConfiguration() {
        RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration();
        sentinelConfig.setMaster(masterName);

        Set<RedisNode> sentinelNodes = new HashSet<>();
        if (StringUtils.hasText(nodes)) {
            String[] nodeArray = nodes.split(",");
            for (String node : nodeArray) {
                String[] parts = node.trim().split(":");
                if (parts.length == 2) {
                    sentinelNodes.add(new RedisNode(parts[0], Integer.parseInt(parts[1])));
                }
            }
        }
        sentinelConfig.setSentinels(sentinelNodes);

        if (StringUtils.hasText(password)) {
            sentinelConfig.setPassword(password);
        }

        return sentinelConfig;
    }

    /**
     * 配置 LettuceConnectionFactory 实现读写分离
     * 注意：对于 Sentinel 模式，Spring Boot 会自动创建 RedisSentinelConfiguration。
     * 这里手动创建是为了配置 LettuceClientConfiguration 的 ReadFrom 策略。
     */
    @Bean
    public LettuceConnectionFactory redisConnectionFactory(RedisSentinelConfiguration sentinelConfiguration) {
        // 1. 配置 Lettuce 客户端以支持读写分离
        LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
                .readFrom(ReadFrom.REPLICA_PREFERRED) // 优先从从节点读取，如果不可用则从主节点读取
                // .readFrom(ReadFrom.LOWEST_LATENCY) // Redis 6.0+ 可以使用此策略，从延迟最低的节点读取
                .commandTimeout(Duration.ofMillis(5000)) // 命令超时
                // 其他客户端配置，如 SSL、连接池等
                .build();

        // 2. 创建 LettuceConnectionFactory
        // Spring Boot 2.x 以后，如果配置了 sentinel，会自动注入 RedisSentinelConfiguration
        return new LettuceConnectionFactory(sentinelConfiguration, clientConfiguration);
    }

    /**
     * 配置 RedisTemplate，使用 JSON 序列化器
     */
    @Bean("master-slave")
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        // 使用 StringRedisSerializer 来序列化和反序列化 Redis 的 key 值
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());

        // 使用 GenericJackson2JsonRedisSerializer 来序列化和反序列化 Redis 的 value 值
        // 这使得你可以存储 Java 对象为 JSON 字符串，并自动反序列化
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        template.setValueSerializer(jsonRedisSerializer);
        template.setHashValueSerializer(jsonRedisSerializer);

        template.afterPropertiesSet();
        return template;
    }
}
